package educrypt.commons;

import educrypt.analysis.AnalysisNgrams;
import educrypt.commons.util.TextUtil;

public class Alphabet {
	private String name;
	private String symbols;

	// Transforms a string of symbols into a valid alphabet
	// All symbols lower case, no white spaces, no repeated symbols
	public static String formatSymbols(String symbols) {
		symbols = symbols.toLowerCase();
		symbols = TextUtil.removeWhiteSpaces(symbols);
		symbols = TextUtil.removeRepeatedSymbols(symbols);
		return symbols;
	}

	public Alphabet(String name, String symbols) {
		this.name = name;
		this.symbols = symbols;
	}

	public char getSymbolAt(int pos) {
		return symbols.charAt(pos);
	}

	public int getSymbolPosition(char symbol) {
		return symbols.indexOf(Character.toLowerCase(symbol));
	}

	public int[] getSymbolsPosition(String data) {
		int[] symbolsPosition = new int[data.length()];
		for (int i = 0; i < data.length(); i++) {
			char symbol = data.charAt(i);
			symbolsPosition[i] = this.getSymbolPosition(symbol);
		}
		return symbolsPosition;
	}

	public int size() {
		return this.symbols.length();
	}

	public boolean testBelonging(String dataToTest) {
		dataToTest = dataToTest.toLowerCase();
		boolean belongsToAlphabet = true;
		for (int i = 0; i < dataToTest.length(); i++) {
			belongsToAlphabet = belongsToAlphabet
					&& containsSymbol(dataToTest.charAt(i));
		}
		return belongsToAlphabet;
	}

	public boolean containsSymbol(char symbol) {
		symbol = Character.toLowerCase(symbol);
		return (this.symbols.indexOf(symbol) != -1 ? true : false);
	}

	// Me devuelve una cadena solo con los simbolos conocidos
	// Mayusculas y minusculas no alteradas y no diferenciadas al comparar
	public String filterKnownSymbols(String toFilter) {
		StringBuffer filteredData = new StringBuffer();
		for (char symbol : toFilter.toCharArray()) {
			if (this.containsSymbol(symbol)) {
				filteredData.append(symbol);
			}
		}
		return filteredData.toString();
	}

	// For keys generation
	public Alphabet rotate(int offset) {
		Alphabet rotatedAlphabet = new Alphabet(this.name,
				TextUtil.rotateString(this.symbols, offset));
		return rotatedAlphabet;
	}

	public Alphabet getCopyBeginningWith(String symbols) {
		String newSymbols = Alphabet.formatSymbols(symbols + this.symbols);
		return new Alphabet(this.name, newSymbols);

	}

	public AnalysisNgrams generatePermutations(int length) {
		AnalysisNgrams permutations = new AnalysisNgrams();
		for (char symbol : this.symbols.toCharArray()) {
			permutations.addNgram(Character.toString(symbol));
		}
		permutations = addSymbolsToPermutation(permutations, length - 1);
		return permutations;
	}

	private AnalysisNgrams addSymbolsToPermutation(AnalysisNgrams permutations,
			int numberOfSymbolsToAdd) {
		AnalysisNgrams permutationsAux = new AnalysisNgrams();
		if (numberOfSymbolsToAdd == 0) { // Base case
			permutationsAux = permutations;
		} else if (numberOfSymbolsToAdd > 0) {
			for (int i = 0; i < this.symbols.length(); i++) {
				char symbol = this.symbols.charAt(i);
				for (String base : permutations) {
					permutationsAux.addNgram(base + symbol);
				}
			}
			permutationsAux = this.addSymbolsToPermutation(permutationsAux,
					numberOfSymbolsToAdd - 1);
		}
		return permutationsAux;
	}

	public String symbolsAt(int[] positions) {
		String symbols = "";
		for (int pos : positions) {
			symbols += this.getSymbolAt(pos);
		}
		return symbols;

	}

	public String getName() {
		return this.name;
	}

	public String getSymbols() {
		return this.symbols;
	}
}